package com.jubaozan.c3.framework.logs;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


import lombok.extern.slf4j.Slf4j;

/**
 * @author jiangjinwu
 * @version 1.0
 * @since 2025/10/7 18:08
 */

@Slf4j

public class UtilElk {
  private static final Set<String> LOGGER_CLASSES = new HashSet<>(Collections.singletonList("com.mongodb.diagnostics.logging.SLF4JLogger"));
  public static final Charset CHARSET = StandardCharsets.UTF_8;
  public static final Integer JVM_PID = Integer.valueOf(getRuntimeMXBean().getName().split("@", 2)[0]);
  public static final String HOST_IP = getHostIp();
  public static final String MESSAGE_NULL_VAL = "-";
  public static final String LINESEPARATOR_DEFAULT = "\n";
  public static final String LINESEPARATOR;
  public static final byte[] LINESEPARATOR_BYTES;

  static {
    String lineSeparator = System.lineSeparator();
    LINESEPARATOR = lineSeparator == null ? LINESEPARATOR_DEFAULT : lineSeparator;
    LINESEPARATOR_BYTES = LINESEPARATOR.getBytes(CHARSET);
  }

  private UtilElk() {
  }

  private static RuntimeMXBean getRuntimeMXBean() {
    return ManagementFactory.getRuntimeMXBean();
  }

  public static String toStr(Object v) {
    return v == null ? null : v.toString();
  }

  public static void put(Map<String, Object> map, String key, Object value) {
    if (key != null && value != null) {
      map.put(key, value);
    }
  }

  public static String formatDate(long timestamp) {
    DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
    format.setTimeZone(TimeZone.getDefault());
    return format.format(new Date(timestamp));
  }

  public static Map<String, Object> getSource(StackTraceElement... stacks) {
    StackTraceElement stack = getCaller(stacks);
    if (stack == null) return null;

    Map<String, Object> map = new HashMap<>();
    map.put("class", stack.getClassName());
    map.put("method", stack.getMethodName());
    map.put("file", stack.getFileName());
    map.put("line", stack.getLineNumber());
    return map;
  }

  private static StackTraceElement getCaller(StackTraceElement[] stacks) {
    if (stacks == null || stacks.length == 0) return null;

    for (StackTraceElement stack : stacks) {
      if (stack == null) continue;

      if (!LOGGER_CLASSES.contains(stack.getClassName())) {
        return stack;
      }
    }
    return stacks[0];
  }

  /**
   * 从当前机器获取的最优主机ip地址<br>
   * <ol>
   * 	<li>null: InetAddress.getLocalHost()</li>
   * 	<li>一个ip时: ip</li>
   * 	<li>-Dspring.cloud.consul.discovery.ip-address</li>
   * 	<li>-Dspring.cloud.inetutils.preferred-networks</li>
   * 	<li>10.</li>
   * 	<li>172.</li>
   * 	<li>192.</li>
   * 	<li>InetAddress.getLocalHost()</li>
   * </ol>
   */
  private static String getHostIp() {
    LinkedHashMap<InetAddress, NetworkInterface> all = getAllIp();
    if (all.isEmpty()) return getLocalHostAddress();

    List<String> ips = all.keySet().stream().map(InetAddress::getHostAddress).collect(Collectors.toList());
    if (ips.size() == 1) return ips.get(0);

    // find consul
    String ipConsul = System.getProperty("spring.cloud.consul.discovery.ip-address", "").trim(), ip10 = null, ip172 = null, ip192 = null;
    for (String ip : ips) {
      if (ip.equals(ipConsul)) return ipConsul;

      if (ip10 == null && ip.startsWith("10.")) ip10 = ip;
      if (ip172 == null && ip.startsWith("172.")) ip172 = ip;
      if (ip192 == null && ip.startsWith("192.")) ip192 = ip;
    }

    // find cloud
    for (String net : getSpringCloudPreferredNetworks()) {
      for (String ip : ips) {
        if (ip.startsWith(net) || ip.matches(net)) return ip;
      }
    }

    if (ip10 != null) return ip10;
    if (ip172 != null) return ip172;
    if (ip192 != null) return ip192;
    return getLocalHostAddress();
  }

  private static Set<String> getSpringCloudPreferredNetworks() {
    Set<String> result = new LinkedHashSet<>();
    String value = System.getProperty("spring.cloud.inetutils.preferred-networks");
    if (value == null || value.isEmpty()) return result;

    int pos = 0;
    for (int i = 0, len = value.length(); i < len; i++) {
      char ch = value.charAt(i);
      if ((ch < '0' || ch > '9') && ch != '.') {
        String ip = value.substring(pos, i).trim();
        pos = i + 1;
        if (!ip.isEmpty()) result.add(ip);
      }
    }
    if (pos < value.length()) {
      String ip = value.substring(pos).trim();
      if (!ip.isEmpty()) result.add(ip);
    }
    return result;
  }

  /**
   * 获取所有的ip地址
   */
  private static LinkedHashMap<InetAddress, NetworkInterface> getAllIp() {
    LinkedHashMap<InetAddress, NetworkInterface> addrMap = new LinkedHashMap<>();
    try {
      for (Enumeration<NetworkInterface> iter = NetworkInterface.getNetworkInterfaces(); iter.hasMoreElements(); ) {
        NetworkInterface net = iter.nextElement();
        if (!net.isUp() || net.isLoopback()) continue;

        for (Enumeration<InetAddress> iter2 = net.getInetAddresses(); iter2.hasMoreElements(); ) {
          InetAddress addr = iter2.nextElement();
          if (addr instanceof Inet4Address) {
            addrMap.put(addr, net);
          }
        }
      }
    } catch (SocketException e) {
      throw new IllegalStateException(e);
    }
    return addrMap;
  }

  /**
   * InetAddress.getLocalHost().getHostAddress()
   */
  private static String getLocalHostAddress() {
    try {
      return InetAddress.getLocalHost().getHostAddress();
    } catch (UnknownHostException e) {
      throw new IllegalStateException(e);
    }
  }

  public static String getAppId() {
    String appId = System.getProperty("@appId");
    if (appId == null) appId = System.getenv("pom_a");
    return appId;
  }

  public static boolean notEmpty(Map<?, ?> map) {
    return map != null && !map.isEmpty();
  }

}
